package com.etonenet.controller.handler;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import com.etonenet.expection.BossException;
import com.etonenet.util.ServletUtil;

@ControllerAdvice
public class CustomExceptionHandler implements HandlerExceptionResolver {

	private Logger logger = LoggerFactory.getLogger(getClass());

	public static final String ILLEGAL_ARGUMENT = "ILLEGAL_ARGUMENT";
	public static final String UNKOWN_EXCEPTION = "UNKOWN_EXCEPTION";

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
		logger.error("", ex);

		if (!ServletUtil.isXhr(request)) {
			ModelAndView mv = new ModelAndView("redirect:/500");
			return mv;
		} else {

			ModelAndView mv = new ModelAndView();
			MappingJackson2JsonView mjjv = new MappingJackson2JsonView();

			if (ex instanceof BossException) {
				mjjv.setAttributesMap(errorMap(((BossException) ex).getType(), ex.getMessage()));
			} else
				mjjv.setAttributesMap(errorMap(UNKOWN_EXCEPTION, ex.getMessage()));

			mv.setView(mjjv);
			return mv;
		}
	}

	/**
	 * controller在@requestBody@valid参数检验不通过后错误处理
	 * 
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ResponseBody
	public Map<String, String> methodArgumentNotValidException(MethodArgumentNotValidException ex) {

		StringBuffer sb = new StringBuffer();
		for (ObjectError oe : ex.getBindingResult().getAllErrors()) {
			if (oe instanceof FieldError) {
				FieldError e = (FieldError) oe;
				sb.append(e.getField() + ":" + e.getDefaultMessage());
			} else
				sb.append(oe.getDefaultMessage());
		}
		return errorMap(ILLEGAL_ARGUMENT, sb.toString());
	}

	/**
	 * controller在@modalAttribute@valid参数检验不通过后错误处理
	 * 
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(BindException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ResponseBody
	public Map<String, String> bindException(BindException ex) {

		StringBuffer sb = new StringBuffer();
		for (ObjectError oe : ex.getBindingResult().getAllErrors()) {
			if (oe instanceof FieldError) {
				FieldError e = (FieldError) oe;
				sb.append(e.getField() + ":" + e.getDefaultMessage());
			} else
				sb.append(oe.getDefaultMessage());
		}
		return errorMap(ILLEGAL_ARGUMENT, sb.toString());
	}

	private Map<String, String> errorMap(String error, String errorDescription) {
		Map<String, String> m = new LinkedHashMap<String, String>();
		m.put("error", error);
		m.put("error_description", errorDescription);
		return m;
	}
}
